//
//  TSCLinerLayout2.m
//  Tsc_IOS
//
//  Created by ZhengRui on 15/8/16.
//  Copyright © 2015年 idream. All rights reserved.
//
// == 编写说明
// 2015-08-16 Rio
// 这段时间被IOS的布局搞惨了，这就是典型的“搜索式学习方法”：知识点不是系统学习得来的（比如参考官方文档），而是用到什么、不会什么，就去搜索什么。搜索到的技巧又不是最新的，很可能是过时的，再加上自己亲自动手去写，渐渐进入了死胡同。我这几个月，基本上经历了IOS对于布局的三个发展阶段：
// 1. frame时代：所有UI元素的位置都是通过手工计算，并设置在frame上的。以前之所以这么弄，完全是因为当时的IOS设备尺寸是固定的，一切都可以通过frame进行计算并设置。
// 2. AutoLayout时代：AutoLayout技术刚刚出现，但它只能设定一种情况：当父view大小发生变化时，其子view的大小、位置该如何变化？但它解决不了各个子view之间、子view同父view之间的相对关系问题。
// 3. AutoLayout+SizeClassed时代：这是一个全新的时代！意味着frame时代的终结！我们再也不用，也不能通过frame进行UI元素的布局了。因为IOS设备的显示尺寸不只有一种了。
// 3.1 首先，通过AutoLayout，可以解决子view与父view之间、各个子view之间的相对位置、大小。
// 3.2 其次，通过SizeClasses可以解决在不同尺寸的设备上，或者横屏、竖屏显示的问题。
// 3.3 最后，IOS 9中新增的UIStackView，解决了最后一个问题：如果“动态地”添加、删除子view，各个子view之间、子view与父view之间的关系、大小，该怎么办？
// 鉴于目前主流苹果设备依然使用IOS 8，所以，暂时还不能采用UIStackView。那么，为了解决问题3.3，就自己写了这个类。
//
//
// == 使用注意：
// 1. 因为LinearLayout自行管理的约束，会将”直接子view“的4个边，紧贴LinearLayout自身的4个边，所以，为了使LinearLayout最终的size不为零，则可以：
//   1.1 指定LinearLayout.frame.size
//   1.2 指定LinearLayout的宽度约束、高度约束
//   1.3 指定直接子view的frame.size
//   1.4 指定直接子view的子view（或者更深层子view）的frame.size
//   1.5 指定直接子view的子view（或者更深层子view）的宽度约束、高度约束
//   但不能：
//   1.6 指定直接子view的宽度、高度约束。因为这会与LinearLayout自行管理的约束冲突，导致UI显示混乱！
// 2. 如果给直接子view指定了frame.width、frame.height，则将这个宽度、高度，当做直接子view的宽度约束、高度约束
// 3. 如果想达到LinearyLayout宽度、高度，随子view宽度、高度、数量来”动态“变化（比如包含GCSelector的Dialog），应当这样做：
//   3.1 让Dialog继承LinearLayout，orientation为垂直。并为Dialog添加约束：left约束、right约束、Y轴居中
//   3.2 Dialog中的每一行row不添加约束（即LinearLayout的直接子view不添加约束）。此时，每一行row的宽度将自动等于LinearLayout的宽度
//   3.3 row中的每一个子view可以添加宽度约束，比如row中添加3个spinner，并添加等宽的宽度约束
//   3.4 row中的每一个子view可以添加left、top、right、bottom 4个约束，并添加高度约束，从而”间接地“将row撑高
//
//
// == TODO
// -- TODO 动画：由外部使用者控制
// -- TODO 自定义两个padding
// -- TODO 横向、纵向都支持


#import <Foundation/Foundation.h>
#import "TSCLinearLayout.h"

@implementation TSCLinearLayout {
    //    NSMutableDictionary * _svHasRemovedManually; // key: 每一个“将要”被删除的子view的内存地址字符串；value：1 // 表示这个子view已经在该程序中手工移除，而不必再次调用父类监听子view将要被移除的回调，避免死循环
    
    NSMutableDictionary * _allSelfConstraints; // 其本身可以理解为一个二维数组。key: 每一个子view的内存地址字符串，用来快速定位到保存这个子view在4个方向上约束的字典；value：具有left、top、right、bottom 4个键值的字典，用来记录这个子view在左、上、右、下4个方向上的约束情况
    
    NSMutableArray * _uiEArrUnequal; // 设置了frame，或者distribution属性为NONE的ui元素数组（比如Dialog的btnPanel中的竖线）
    NSMutableArray * _uiEArrEqual; // 没有设置frame，且distribution属性为FILL_EQUALLY的ui元素数组（比如Dialog的btnPanel中的3个等宽按钮）
}

#pragma mark 初始化

- (id) initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self initLinerLayout];
    }
    return self;
}

- (id) init {
    self = [self initWithFrame:CGRectMake(0, 0, 0, 0)];
    return self;
}

- (id) initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self initLinerLayout];
    }
    return self;
}

/* private */ - (void) initLinerLayout {
    //    _svHasRemovedManually = [[NSMutableDictionary alloc]init];
    _allSelfConstraints = [[NSMutableDictionary alloc]init];
    _uiEArrUnequal = [[NSMutableArray alloc]init];
    _uiEArrEqual = [[NSMutableArray alloc]init];
    _paddingC2F = 0.0f; // 默认值：0
    _paddingC2C = 0.0f; // 默认值：0
    _orientation = LINEAR_LAYOUT_ORIENTATION_VERTICAL; // 默认值：纵向
    _distribution = LINEAR_LAYOUT_DISTRIBUTION_NONE; // 默认值：无
}


#pragma mark 私有方法

// ===== 垂直布局

// 当有新的子view“已经被”添加到自身时，调用该方法
/* private */ - (void) reApplySelfConstraintsAfterAddedSubview_V:(UIView *) subview {
    
    // 获得当前全部子view数组
    // 注：进入该方法后，表示子view已经添加到父view了，所以subviews个数应该是1
    NSArray * svArr = [self subviews];
    
    // 找到上一个兄弟view
    UIView * preSibling = [self findPreviousSiblingInSubviewArr:svArr forSubview:subview];
    
    // 创建子view约束
    subview.translatesAutoresizingMaskIntoConstraints = NO;
    // left
    NSLayoutConstraint * leftCt = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:_paddingC2F];
    // top
    NSLayoutConstraint * topCt = nil;
    if (preSibling == nil) {  // 1 增加的子view，是第一个子view，其上直接对其父view top
        topCt = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:_paddingC2F];
    } else { // 2 增加的子view，不是第一个子view，其上对应父view中的最后一个子view
        // 2.1 解除上一个兄弟view的bottom边上的旧约束
        
        // 将兄弟view的bottom约束禁止
        // 注：IOS API中不建议使用约束的删除，而建议使用约束的禁止，并警告约束的删除API将来会被删掉。保险起见，我们先遵从这一约定
        NSMutableDictionary * preSiblingCtDic = [_allSelfConstraints objectForKey:[NSString stringWithFormat:@"%p", preSibling]];
        NSLayoutConstraint * ct = [preSiblingCtDic objectForKey:LINEAR_LAYOUT_CONSTRAINT_KEY_BOTTOM];
        ct.active = NO;
        
        topCt = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:preSibling attribute:NSLayoutAttributeBottom multiplier:1.0f constant:_paddingC2C];
    }
    // right
    NSLayoutConstraint * rightCt = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:-_paddingC2F];
    // bottom
    NSLayoutConstraint * bottomCt = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0f constant:-_paddingC2F];
    // width
    NSLayoutConstraint * widthCt = nil;
    if (subview.frame.size.width > 0) {
        widthCt = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:subview.frame.size.width];
    }
    // height
    NSLayoutConstraint * heightCt = nil;
    if (subview.frame.size.height > 0) { // 设置了frame：高优先级
        // 将待添加ui元素A添加到_uiEArrUnequal[]
        [_uiEArrUnequal addObject:subview];
        
        // 根据frame设定高度约束
        heightCt = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:subview.frame.size.height];
    } else { // 没有设置frame：低优先级
        switch (_distribution) {
            case LINEAR_LAYOUT_DISTRIBUTION_NONE: {
//                NSLog(@"[W]%s: 既没有指定子view[%@]的frame.size.height，又没有设置父view[%@]的distribution属性，可能导致子view布局混乱！你确定已手工设置了子view的高度约束？", __FUNCTION__, subview, self);
                
                // TODO 有一种情况，就是外部使用者自行给子view添加了约束，
                // 或者子view虽然没有设置height，也没有设置height约束，但子view的子view却通过约束撑起子view（比如将GCSelector添加到Dialog的customView），
                // 这时不必报warning，高度约束也不会有任何问题
                
                break;
            }
            case LINEAR_LAYOUT_DISTRIBUTION_FILL_EQUALLY: {
                // 找到_uiEArrEqual[]中的第一个元素E
                UIView * firstE = nil;
                if ([_uiEArrEqual count] >= 1) {
                    firstE = [_uiEArrEqual objectAtIndex:0];
                }
                
                // 对_uiEArrEqual[]中的每一个元素（包括E）：
                for (UIView * view in _uiEArrEqual) {
                    // 取消旧约束（包括E）：height约束
                    NSMutableDictionary * viewCtDic = [_allSelfConstraints objectForKey:[NSString stringWithFormat:@"%p", view]];
                    NSLayoutConstraint * ctHeightOld = [viewCtDic objectForKey:LINEAR_LAYOUT_CONSTRAINT_KEY_HEIGHT];
                    if (ctHeightOld) {
                        ctHeightOld.active = NO;
                    }
                    
                    // 添加新约束（除E外）：等高于E
                    if (view != firstE) {
                        NSLayoutConstraint * ctHeightNew = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:firstE attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f];
                        ctHeightNew.active = YES;
                        [viewCtDic setObject:ctHeightNew forKey:LINEAR_LAYOUT_CONSTRAINT_KEY_HEIGHT];
                    }
                }
                
                // 对待添加ui元素A添加新约束：等高于E
                if (firstE) {
                    heightCt = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:firstE attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f];
                }
                
                // 将A添加到_uiEArrEqual[]
                [_uiEArrEqual addObject:subview];
                
                break;
            }
            default: {
                NSAssert(1 != 1, @"[E]%s: LinearLayout设置了非法的distribution！", __FUNCTION__);
                break;
            }
        }
    }
    
    // 将子view的4个约束保存在数组中，并应用到自身
    NSMutableDictionary * svCtDic = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                     leftCt, LINEAR_LAYOUT_CONSTRAINT_KEY_LEFT,
                                     topCt, LINEAR_LAYOUT_CONSTRAINT_KEY_TOP,
                                     rightCt, LINEAR_LAYOUT_CONSTRAINT_KEY_RIGHT,
                                     bottomCt, LINEAR_LAYOUT_CONSTRAINT_KEY_BOTTOM,
                                     nil];
    if (widthCt) {
        [svCtDic setObject:widthCt forKey:LINEAR_LAYOUT_CONSTRAINT_KEY_WIDTH];
    }
    if (heightCt) {
        [svCtDic setObject:heightCt forKey:LINEAR_LAYOUT_CONSTRAINT_KEY_HEIGHT];
    }
    [NSLayoutConstraint activateConstraints:[svCtDic allValues]];
    
    // 将子view的约束数组，保存在类属性中
    [_allSelfConstraints setObject:svCtDic forKey:[NSString stringWithFormat:@"%p", subview]];
}

// 当某个子view“将要被”从自身移除时，调用该方法
/* private */ - (void) reApplySelfConstraintsAfterDeletedSubview_V:(UIView *) subview {
    
    // 获得当前全部子view数组
    // 注：必须确保调用此方法时，“将要被”删除的子view，还没有真正从父view中移除，否则[self subviews]将无法获得“将要被”删除的子view
    NSArray * svArr = [self subviews];
    
    // 找到上一个、下一个兄弟view
    UIView * preSibling = [self findPreviousSiblingInSubviewArr:svArr forSubview:subview];
    UIView * nextSibling = [self findNextSiblingInSubviewArr:svArr forSubview:subview];
    
    // == 第一步：设置left、top、right、bottom约束
    
    // 禁止子view的全部约束
    NSMutableDictionary * svCtDic = [_allSelfConstraints objectForKey:[NSString stringWithFormat:@"%p", subview]];
    for (NSLayoutConstraint * ct in [svCtDic allValues]) {
        ct.active = NO;
    }
    
    // 1 [上兄弟-有；下兄弟-有]：当前“将要被”删除的子view处于两个子view中间
    if (preSibling && nextSibling) {
        // 将上一个兄弟view的bottom，连接到下一个兄弟view的top上
        NSMutableDictionary * nextSiblingCtDic = [_allSelfConstraints objectForKey:[NSString stringWithFormat:@"%p", nextSibling]];
        NSLayoutConstraint * nextSiblingCt = [nextSiblingCtDic objectForKey:LINEAR_LAYOUT_CONSTRAINT_KEY_TOP];
        nextSiblingCt.active = NO;
        
        NSLayoutConstraint * nextSiblingCtTop = [NSLayoutConstraint constraintWithItem:nextSibling attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:preSibling attribute:NSLayoutAttributeBottom multiplier:1.0f constant:_paddingC2C];
        nextSiblingCtTop.active = YES;
        
        // 更新子view的约束数组
        [nextSiblingCtDic setObject:nextSiblingCtTop forKey:LINEAR_LAYOUT_CONSTRAINT_KEY_TOP];
    }
    // 2 [上兄弟-有；下兄弟-无]：当前“将要被”删除的子view处于父view最后
    else if (preSibling && !nextSibling) {
        // 将上一个兄弟view的bottom，连接父view的bottom上
        NSMutableDictionary * preSiblingCtDic = [_allSelfConstraints objectForKey:[NSString stringWithFormat:@"%p", preSibling]];
        NSLayoutConstraint * preSiblingCt = [preSiblingCtDic objectForKey:LINEAR_LAYOUT_CONSTRAINT_KEY_BOTTOM];
        preSiblingCt.active = NO;
        
        NSLayoutConstraint * preSiblingCtBottom = [NSLayoutConstraint constraintWithItem:preSibling attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0f constant:-_paddingC2F];
            preSiblingCtBottom.active = YES;
        
        // 更新子view的约束数组
        [preSiblingCtDic setObject:preSiblingCtBottom forKey:LINEAR_LAYOUT_CONSTRAINT_KEY_BOTTOM];
    }
    // 3 [上兄弟-无；下兄弟-有]：当前“将要被”删除的子view处于第一个子view
    else if (!preSibling && nextSibling) {
        // 将下一个兄弟view的top，连接到父view的top上
        NSMutableDictionary * nextSiblingCtDic = [_allSelfConstraints objectForKey:[NSString stringWithFormat:@"%p", nextSibling]];
        NSLayoutConstraint * nextSiblingCt = [nextSiblingCtDic objectForKey:LINEAR_LAYOUT_CONSTRAINT_KEY_TOP];
        nextSiblingCt.active = NO;
        
        NSLayoutConstraint * nextSiblingCtTop = [NSLayoutConstraint constraintWithItem:nextSibling attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:_paddingC2F];
        nextSiblingCtTop.active = YES;
        
        // 更新子view的约束数组
        [nextSiblingCtDic setObject:nextSiblingCtTop forKey:LINEAR_LAYOUT_CONSTRAINT_KEY_TOP];
    }
    // 4 [上兄弟-无；下兄弟-无]：当前“将要被”删除的子view是唯一的子view
    else {
        // do nothing
    }
    
    // == 第二步：重新设置height约束
    
    // 1 如果将要删除view的是_uiEArrUnequal[]类元素
    if ([_uiEArrUnequal containsObject:subview]) {
        // 从_uiEArrUnequal[]中移除
        [_uiEArrUnequal removeObject:subview];
    }
    // 2 如果将要删除的是_uiEArrEqual[]类元素
    else {
        // 从_uiEArrEqual[]中移除
        [_uiEArrEqual removeObject:subview];
        
        // 找到_uiEArrEqual[]中第一个ui元素A
        UIView * firstA = nil;
        if ([_uiEArrEqual count] >= 1) {
            firstA = [_uiEArrEqual objectAtIndex:0];
        }
        
        // 对于_uiEArrEqual[]中的每一个ui元素（包括A）：
        for (UIView * view in _uiEArrEqual) {
            // 取消旧约束（包括A）：height约束
            NSMutableDictionary * viewCtDic = [_allSelfConstraints objectForKey:[NSString stringWithFormat:@"%p", view]];
            NSLayoutConstraint * ctHeightOld = [viewCtDic objectForKey:LINEAR_LAYOUT_CONSTRAINT_KEY_HEIGHT];
            if (ctHeightOld) {
                ctHeightOld.active = NO;
            }
            
            // 添加新约束（除A外）：等高于A
            if (view != firstA) {
                NSLayoutConstraint * ctHeightNew = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:firstA attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f];
                ctHeightNew.active = YES;
                [viewCtDic setObject:ctHeightNew forKey:LINEAR_LAYOUT_CONSTRAINT_KEY_HEIGHT];
            }
        }
    }
}

// ===== 水平布局

// 当有新的子view“已经被”添加到自身时，调用该方法
/* private */ - (void) reApplySelfConstraintsAfterAddedSubview_H:(UIView *) subview {
    
    // 获得当前全部子view数组
    // 注：进入该方法后，表示子view已经添加到父view了，所以subviews个数应该是1
    NSArray * svArr = [self subviews];
    
    // 找到上一个兄弟view
    UIView * preSibling = [self findPreviousSiblingInSubviewArr:svArr forSubview:subview];
    
    // 创建子view约束
    subview.translatesAutoresizingMaskIntoConstraints = NO;
    // left
    NSLayoutConstraint * leftCt = nil;
    if (preSibling == nil) { // 1 增加的子view，是第一个子view，其左直接对其父view left
        leftCt = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:_paddingC2F];
    } else { // 2 增加的子view，不是第一个子view，其左对应父view中的最后一个子view
        // 2.1 解除上一个兄弟view的right边上的旧约束
        
        // 将兄弟view的right约束禁止
        // 注：IOS API中不建议使用约束的删除，而建议使用约束的禁止，并警告约束的删除API将来会被删掉。保险起见，我们先遵从这一约定
        NSMutableDictionary * preSiblingCtDic = [_allSelfConstraints objectForKey:[NSString stringWithFormat:@"%p", preSibling]];
        NSLayoutConstraint * ct = [preSiblingCtDic objectForKey:LINEAR_LAYOUT_CONSTRAINT_KEY_RIGHT];
        ct.active = NO;
        
        leftCt = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:preSibling attribute:NSLayoutAttributeRight multiplier:1.0f constant:_paddingC2C];
    }
    // top
    NSLayoutConstraint * topCt = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:_paddingC2F];
    // right
    NSLayoutConstraint * rightCt = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:-_paddingC2F];
    // bottom
    NSLayoutConstraint * bottomCt = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0f constant:-_paddingC2F];
    NSLayoutConstraint * widthCt = nil;
    if (subview.frame.size.width > 0) { // 设置了frame：高优先级
        // 将待添加ui元素A添加到_uiEArrUnequal[]
        [_uiEArrUnequal addObject:subview];
        
        // 根据frame设定高度约束
        widthCt = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:subview.frame.size.width];
    } else { // 没有设置frame：低优先级
        switch (_distribution) {
            case LINEAR_LAYOUT_DISTRIBUTION_NONE: {
//                NSLog(@"[W]%s: 既没有指定子view[%@]的frame.size.width，又没有设置父view[%@]的distribution属性，可能导致子view布局混乱！你确定已手工设置了子view的宽度约束？", __FUNCTION__, subview, self);
                
                // TODO 有一种情况，就是外部使用者自行给子view添加了约束，这时报warning，不合适吧？
                // TODO 还有一种情况，就是父view LinearLayout设置了宽度约束，子view没有设置frame.width，只是想通过左右约束贴近父view，占满父view。这时报错也不合适
                
                break;
            }
            case LINEAR_LAYOUT_DISTRIBUTION_FILL_EQUALLY: {
                // 找到_uiEArrEqual[]中的第一个元素E
                UIView * firstE = nil;
                if ([_uiEArrEqual count] >= 1) {
                    firstE = [_uiEArrEqual objectAtIndex:0];
                }
                
                // 对_uiEArrEqual[]中的每一个元素（包括E）：
                for (UIView * view in _uiEArrEqual) {
                    // 取消旧约束（包括E）：height约束
                    NSMutableDictionary * viewCtDic = [_allSelfConstraints objectForKey:[NSString stringWithFormat:@"%p", view]];
                    NSLayoutConstraint * ctWidthOld = [viewCtDic objectForKey:LINEAR_LAYOUT_CONSTRAINT_KEY_WIDTH];
                    if (ctWidthOld) {
                        ctWidthOld.active = NO;
                    }
                    
                    // 添加新约束（除E外）：等高于E
                    if (view != firstE) {
                        NSLayoutConstraint * ctWidthNew = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:firstE attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0.0f];
                        ctWidthNew.active = YES;
                        [viewCtDic setObject:ctWidthNew forKey:LINEAR_LAYOUT_CONSTRAINT_KEY_WIDTH];
                    }
                }
                
                // 对待添加ui元素A添加新约束：等高于E
                if (firstE) {
                    widthCt = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:firstE attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0.0f];
                }
                
                // 将A添加到_uiEArrEqual[]
                [_uiEArrEqual addObject:subview];
                
                break;
            }
            default: {
                NSAssert(1 != 1, @"[E]%s: LinearLayout设置了非法的distribution！", __FUNCTION__);
                break;
            }
        }
    }
    NSLayoutConstraint * heightCt = nil;
    if (subview.frame.size.height > 0) {
        heightCt = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:subview.frame.size.height];
    }
    
    // 将子view的4个约束保存在数组中，并应用到自身
    NSMutableDictionary * svCtDic = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                     leftCt, LINEAR_LAYOUT_CONSTRAINT_KEY_LEFT,
                                     topCt, LINEAR_LAYOUT_CONSTRAINT_KEY_TOP,
                                     rightCt, LINEAR_LAYOUT_CONSTRAINT_KEY_RIGHT,
                                     bottomCt, LINEAR_LAYOUT_CONSTRAINT_KEY_BOTTOM,
                                     nil];
    if (widthCt) {
        [svCtDic setObject:widthCt forKey:LINEAR_LAYOUT_CONSTRAINT_KEY_WIDTH];
    }
    if (heightCt) {
        [svCtDic setObject:heightCt forKey:LINEAR_LAYOUT_CONSTRAINT_KEY_HEIGHT];
    }
    [NSLayoutConstraint activateConstraints:[svCtDic allValues]];
    
    // 将子view的约束数组，保存在类属性中
    [_allSelfConstraints setObject:svCtDic forKey:[NSString stringWithFormat:@"%p", subview]];
    
}

// 当某个子view“将要被”从自身移除时，调用该方法
/* private */ - (void) reApplySelfConstraintsAfterDeletedSubview_H:(UIView *) subview {
    
    // 获得当前全部子view数组
    // 注：必须确保调用此方法时，“将要被”删除的子view，还没有真正从父view中移除，否则[self subviews]将无法获得“将要被”删除的子view
    NSArray * svArr = [self subviews];
    
    // 找到上一个、下一个兄弟view
    UIView * preSibling = [self findPreviousSiblingInSubviewArr:svArr forSubview:subview];
    UIView * nextSibling = [self findNextSiblingInSubviewArr:svArr forSubview:subview];
    
    // == 第一步：设置left、top、right、bottom约束
    
    // 禁止子view的全部约束
    NSMutableDictionary * svCtDic = [_allSelfConstraints objectForKey:[NSString stringWithFormat:@"%p", subview]];
    for (NSLayoutConstraint * ct in [svCtDic allValues]) {
        ct.active = NO;
    }
    
    // 1 [上兄弟-有；下兄弟-有]：当前“将要被”删除的子view处于两个子view中间
    if (preSibling && nextSibling) {
        // 将上一个兄弟view的right，连接到下一个兄弟view的left上
        NSMutableDictionary * nextSiblingCtDic = [_allSelfConstraints objectForKey:[NSString stringWithFormat:@"%p", nextSibling]];
        NSLayoutConstraint * nextSiblingCt = [nextSiblingCtDic objectForKey:LINEAR_LAYOUT_CONSTRAINT_KEY_LEFT];
        nextSiblingCt.active = NO;
        
        NSLayoutConstraint * nextSiblingCtLeft = [NSLayoutConstraint constraintWithItem:nextSibling attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:preSibling attribute:NSLayoutAttributeRight multiplier:1.0f constant:_paddingC2C];
        nextSiblingCtLeft.active = YES;
        
        // 更新子view的约束数组
        [nextSiblingCtDic setObject:nextSiblingCtLeft forKey:LINEAR_LAYOUT_CONSTRAINT_KEY_LEFT];
    }
    // 2 [上兄弟-有；下兄弟-无]：当前“将要被”删除的子view处于父view最后
    else if (preSibling && !nextSibling) {
        // 将上一个兄弟view的right，连接父view的right上
        NSMutableDictionary * preSiblingCtDic = [_allSelfConstraints objectForKey:[NSString stringWithFormat:@"%p", preSibling]];
        NSLayoutConstraint * preSiblingCt = [preSiblingCtDic objectForKey:LINEAR_LAYOUT_CONSTRAINT_KEY_RIGHT];
        preSiblingCt.active = NO;
        
        NSLayoutConstraint * preSiblingCtRight = [NSLayoutConstraint constraintWithItem:preSibling attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:-_paddingC2F];
        preSiblingCtRight.active = YES;
        
        // 更新子view的约束数组
        [preSiblingCtDic setObject:preSiblingCtRight forKey:LINEAR_LAYOUT_CONSTRAINT_KEY_RIGHT];
    }
    // 3 [上兄弟-无；下兄弟-有]：当前“将要被”删除的子view处于第一个子view
    else if (!preSibling && nextSibling) {
        // 将下一个兄弟view的left，连接到父view的left上
        NSMutableDictionary * nextSiblingCtDic = [_allSelfConstraints objectForKey:[NSString stringWithFormat:@"%p", nextSibling]];
        NSLayoutConstraint * nextSiblingCt = [nextSiblingCtDic objectForKey:LINEAR_LAYOUT_CONSTRAINT_KEY_LEFT];
        nextSiblingCt.active = NO;
        
        NSLayoutConstraint * nextSiblingCtLeft = [NSLayoutConstraint constraintWithItem:nextSibling attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:_paddingC2F];
        nextSiblingCtLeft.active = YES;
        
        // 更新子view的约束数组
        [nextSiblingCtDic setObject:nextSiblingCtLeft forKey:LINEAR_LAYOUT_CONSTRAINT_KEY_LEFT];
    }
    // 4 [上兄弟-无；下兄弟-无]：当前“将要被”删除的子view是唯一的子view
    else {
        // do nothing
    }
    
    // == 第二步：重新设置width约束
    
    // 1 如果将要删除view的是_uiEArrUnequal[]类元素
    if ([_uiEArrUnequal containsObject:subview]) {
        // 从_uiEArrUnequal[]中移除
        [_uiEArrUnequal removeObject:subview];
    }
    // 2 如果将要删除的是_uiEArrEqual[]类元素
    else {
        // 从_uiEArrEqual[]中移除
        [_uiEArrEqual removeObject:subview];
        
        // 找到_uiEArrEqual[]中第一个ui元素A
        UIView * firstA = nil;
        if ([_uiEArrEqual count] >= 1) {
            firstA = [_uiEArrEqual objectAtIndex:0];
        }
        
        // 对于_uiEArrEqual[]中的每一个ui元素（包括A）：
        for (UIView * view in _uiEArrEqual) {
            // 取消旧约束（包括A）：width约束
            NSMutableDictionary * viewCtDic = [_allSelfConstraints objectForKey:[NSString stringWithFormat:@"%p", view]];
            NSLayoutConstraint * ctWidthOld = [viewCtDic objectForKey:LINEAR_LAYOUT_CONSTRAINT_KEY_WIDTH];
            if (ctWidthOld) {
                ctWidthOld.active = NO;
            }
            
            // 添加新约束（除A外）：等宽于A
            if (view != firstA) {
                NSLayoutConstraint * ctWidthNew = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:firstA attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0.0f];
                ctWidthNew.active = YES;
                [viewCtDic setObject:ctWidthNew forKey:LINEAR_LAYOUT_CONSTRAINT_KEY_WIDTH];
            }
        }
    }
}

/**
 * 找到某个子view的上一个兄弟view
 *
 * @author Rio
 * @date 2015-08-16
 * @return 如果找不到，则返回nil
 *
 */
/* private */ - (UIView *) findPreviousSiblingInSubviewArr:(NSArray *)subviewArr forSubview:(UIView *)view {
    
    for (NSUInteger i = 0, max = [subviewArr count]; i < max; i++) {
        if (subviewArr[i] == view) {
            // 该子view是父view的第一个子view，没有上一个兄弟view
            if (i == 0) {
                return nil;
            }
            // 返回上一个兄弟view
            else {
                return subviewArr[i - 1];
            }
        }
    }
    
    // 连这个子view都没找到，更不用找上一个兄弟view了
    return nil;
}

/**
 * 找到某个子view的下一个兄弟view
 *
 * @author Rio
 * @date 2015-08-16
 * @return 如果找不到，则返回nil
 *
 */
/* private */ - (UIView * ) findNextSiblingInSubviewArr:(NSArray *)subviewArr forSubview:(UIView *)view {
    for (NSUInteger i = 0, max = [subviewArr count]; i < max; i++) {
        if (subviewArr[i] == view) {
            // 该子view是父view的最后一个子view，没有下一个兄弟view
            if (i == (max - 1)) {
                return nil;
            }
            // 返回上一个兄弟view
            else {
                return subviewArr[i + 1];
            }
        }
    }
    
    // 连这个子view都没找到，更不用找下一个兄弟view了
    return nil;
}

#pragma mark 当添加/删除子view时的回调方法

// 注：进入该方法后，表示子view已经添加到父view了
- (void) didAddSubview:(UIView *)subview {
    
    // 重置约束
    if (_orientation == LINEAR_LAYOUT_ORIENTATION_VERTICAL) {
        [self reApplySelfConstraintsAfterAddedSubview_V:subview];
    } else {
        [self reApplySelfConstraintsAfterAddedSubview_H:subview];
    }
    
}


- (void) willRemoveSubview:(UIView *)subview {
    
    // 重置约束
    if (_orientation == LINEAR_LAYOUT_ORIENTATION_VERTICAL) {
        [self reApplySelfConstraintsAfterDeletedSubview_V:subview];
    } else {
        [self reApplySelfConstraintsAfterDeletedSubview_H:subview];
    }
    
    
    //    // 方法一：
    //    // 等待一小段时间后，等待子view从父view彻底移除后，再进行重新布局
    //    //    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    //    ////        [NSThread sleepForTimeInterval:0.00000000000000000001];
    //    //
    //    //        dispatch_async(dispatch_get_main_queue(), ^{
    //    //            [self relayoutSubviewsAndResetSelfWH];
    //    //        });
    //    //    });
    //
    //    // 方法二：
    //    // 参考：http://www.cnblogs.com/dagehaoshuang/p/4012870.html
    //    if ([_svHasRemovedManually objectForKey:[NSString stringWithFormat:@"%p", subview]] == nil) { // 还没有被手工移除
    //        // 标记将要被手工移除
    //        [_svHasRemovedManually setObject:[NSNumber numberWithBool:YES] forKey:[NSString stringWithFormat:@"%p", subview]];
    //
    //        // 重置约束
    //        // 注：必须在真正删除子view之前调用，否则[self subviews]将无法获得已经被删除的子view了
    //        [self reApplySelfConstraintsAfterDeletedSubview:subview];
    //
    //        // 再调用一次removeFromSuperview，这样调用完毕该方法，那么表明该subview已经被移除了
    //        [subview removeFromSuperview];
    //
    //
    //    } else { // 曾被标记手工删除，不再进行删除，直接退出
    //        // 取消标记
    //        [_svHasRemovedManually removeObjectForKey:[NSString stringWithFormat:@"%p", subview]];
    //        return;
    //    }
    
}

@end